home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / shadowmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  10.9 KB  |  448 lines

  1.  
  2. /* shadowmap.c - by Tom McReynolds, SGI */
  3.  
  4. /* Shadows: Shadow volumes. */
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <math.h>
  9. #include <GL/glut.h>
  10.  
  11. /* This program demonstrates shadows on IR using single pass projective
  12.    texture method.  1. Render the scene with light position as the viewpoint
  13.    and save the depth-map into texture image.  2. Use texgen to generate
  14.    texture co-ordinates which are identical to vertex co-ordinates. The
  15.    texture matrix then transforms each pixel coods back to light co-ods. The
  16.    'z' or the depth-value is now available in the 'r' texture co-ordinate.
  17.  
  18.    3. Render the normal scene enabling texgen and shadow texture comparison. 
  19.    Left mouse button: controls rotation of the scene
  20.  
  21.    Right mouse button: controls light (and shadow position) */
  22.  
  23. #define SCENE 10
  24. enum {
  25.   M_NORMAL, M_SHADOW, M_PROJTEX, M_LIGHT
  26. };
  27.  
  28. GLfloat rotv[] =
  29. {0.0, 0.0, 0.0};        /* rotation vector for scene */
  30. GLfloat rotl[] =
  31. {0.0, 0.0, 0.0};        /* rotation vector for light */
  32. GLfloat lv[] =
  33. {10.0, 10.0, 10.0, 1.0};  /* default light position */
  34.  
  35. GLfloat perspective_mat[16], modelview_mat[16], temp[16];
  36. int width = 512, height = 512;
  37. int mouse_button, mouse_state;
  38. static int do_light = 0;
  39. static int do_proj = 0; /* Use projective textures instead of shadows */
  40. /* are shadow extensions supported? */
  41. GLboolean shadows_supported = GL_FALSE;
  42. GLboolean ambient_shadows = GL_FALSE;
  43. GLboolean depth_texture = GL_FALSE;
  44.  
  45. static void generate_shadow_map(void);
  46.  
  47. static void 
  48. reshape(int w, int h)
  49. {
  50.   glViewport(0, 0, w, h);
  51.   width = w;
  52.   height = h;
  53.   glMatrixMode(GL_PROJECTION);
  54.   glLoadIdentity();
  55.   gluPerspective(40.0, (GLfloat) w / (GLfloat) h, 2.0, 30.0);
  56.   glMatrixMode(GL_MODELVIEW);
  57.   glLoadIdentity();
  58.   gluLookAt(0, 0, 15,
  59.     0, 0, 0,
  60.     0, 1, 0);
  61. }
  62.  
  63. /* ARGSUSED1 */
  64. static void 
  65. key(unsigned char key, int x, int y)
  66. {
  67.   switch (key) {
  68.   case '\033':
  69.     exit(0);
  70.   }
  71. }
  72.  
  73. /* ARGSUSED2 */
  74. static void 
  75. mouse(int button, int state, int x, int y)
  76. {
  77.   mouse_button = button;
  78.   mouse_state = state;
  79. }
  80.  
  81. static void 
  82. motion(int x, int y)
  83. {
  84.   if (mouse_state == GLUT_UP)
  85.     return;
  86.  
  87.   switch (mouse_button) {
  88.   case GLUT_LEFT_BUTTON:
  89.     rotv[1] = 180.0 * x / 400.0 - 90.0;
  90.     rotv[0] = 180.0 * y / 400.0 - 90.0;
  91.     break;
  92.   case GLUT_MIDDLE_BUTTON:
  93.     rotl[0] = 180.0 * x / 400.0 - 90.0;
  94.     rotl[1] = 180.0 * y / 400.0 - 90.0;
  95.     break;
  96.   }
  97.   glutPostRedisplay();
  98. }
  99.  
  100. static void 
  101. display(void)
  102. {
  103.   /* Render the scene with the light source as the viewpoint and save the
  104.      depth values in the texture map.  */
  105.   generate_shadow_map();
  106.  
  107.   /* Now render the normal scene using projective textures to get the depth
  108.      value from the light's point of view into the r-cood of the texture.  */
  109.   glEnable(GL_TEXTURE_2D);
  110.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  111.  
  112.   glGetFloatv(GL_PROJECTION_MATRIX, perspective_mat);
  113.   glMatrixMode(GL_TEXTURE);
  114.   glLoadIdentity();
  115.   glTranslatef(0.5, 0.5, 0.4994);
  116.   glScalef(0.5, 0.5, 0.5);
  117.   glMultMatrixf(perspective_mat);
  118.   glMultMatrixf(modelview_mat);
  119.  
  120.   glMatrixMode(GL_MODELVIEW);
  121.   glPushMatrix();
  122.  
  123.   glRotatef(rotv[0], 1, 0, 0);
  124.   glRotatef(rotv[1], 0, 1, 0);
  125.   glRotatef(rotv[2], 0, 0, 1);
  126.   glCallList(SCENE);
  127.  
  128.   glPopMatrix();
  129.   glutSwapBuffers();
  130. }
  131.  
  132. static void 
  133. render_normal_view(void)
  134. {
  135.   glDisable(GL_TEXTURE_2D);
  136.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  137.   glMatrixMode(GL_MODELVIEW);
  138.   glPushMatrix();
  139.   glLoadIdentity();
  140.   gluLookAt(0, 0, 15,
  141.     0, 0, 0,
  142.     0, 1, 0);
  143.   glRotatef(rotv[0], 1, 0, 0);
  144.   glRotatef(rotv[1], 0, 1, 0);
  145.   glRotatef(rotv[2], 0, 0, 1);
  146.   glCallList(SCENE);
  147.  
  148.   glPopMatrix();
  149.   glutSwapBuffers();
  150. }
  151.  
  152. static void 
  153. render_light_view(void)
  154. {
  155.   glDisable(GL_TEXTURE_2D);
  156.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  157.   glMatrixMode(GL_MODELVIEW);
  158.   glPushMatrix();
  159.   glLoadIdentity();
  160.   gluLookAt(lv[0], lv[1], lv[2],
  161.     0, 0, 0,
  162.     0, 1, 0);
  163.   glRotatef(rotl[0], 1, 0, 0);
  164.   glRotatef(rotl[1], 0, 1, 0);
  165.   glRotatef(rotl[2], 0, 0, 1);
  166.   glGetFloatv(GL_MODELVIEW_MATRIX, modelview_mat);
  167.  
  168.   glCallList(SCENE);
  169.   glPopMatrix();
  170.   if (do_light)
  171.     glutSwapBuffers();
  172. }
  173.  
  174. static void 
  175. generate_shadow_map(void)
  176. {
  177.   int x, y;
  178.   GLfloat log2 = log(2.0);
  179.  
  180.   x = 1 << ((int) (log((float) width) / log2));
  181.   y = 1 << ((int) (log((float) height) / log2));
  182.   glViewport(0, 0, x, y);
  183.   render_light_view();
  184.  
  185.   /* Read in frame-buffer into a depth texture map */
  186. #if defined(GL_EXT_subtexture) && defined(GL_EXT_copy_texture)
  187. #ifdef GL_SGIX_depth_texture
  188.   if (do_proj && depth_texture)
  189. #endif
  190.     glCopyTexImage2DEXT(GL_TEXTURE_2D, 0, GL_RGBA,
  191.       0, 0, x, y, 0);
  192. #ifdef GL_SGIX_depth_texture
  193.   else
  194.     glCopyTexImage2DEXT(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_SGIX,
  195.       0, 0, x, y, 0);
  196. #endif
  197. #endif
  198.   glViewport(0, 0, width, height);
  199. }
  200.  
  201. static void 
  202. menu(int mode)
  203. {
  204.   switch (mode) {
  205.   case M_NORMAL:
  206.     do_light = 0;
  207.     do_proj = 0;
  208. #ifdef GL_SGIX_shadow
  209.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_FALSE);
  210. #endif
  211.     glutDisplayFunc(render_normal_view);
  212.     break;
  213.   case M_SHADOW:
  214. #ifdef GL_SGIX_shadow
  215.     do_light = 0;
  216.     do_proj = 0;
  217.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_TRUE);
  218.     glutDisplayFunc(display);
  219. #endif
  220.     break;
  221.   case M_PROJTEX:
  222.     do_light = 0;
  223.     do_proj = 1;
  224. #ifdef GL_SGIX_shadow
  225.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_FALSE);
  226. #endif
  227.     glutDisplayFunc(display);
  228.     break;
  229.   case M_LIGHT:
  230.     do_light = 1;
  231.     if (do_light)
  232.       glutDisplayFunc(render_light_view);
  233.     else
  234.       glutDisplayFunc(display);
  235.     break;
  236.   }
  237.   glutPostRedisplay();
  238. }
  239.  
  240. #define XFORM(cmds) \
  241.   glMatrixMode(GL_TEXTURE); \
  242.   cmds; \
  243.   glMatrixMode(GL_MODELVIEW); \
  244.   cmds
  245.  
  246. static void 
  247. create_scene(void)
  248. {
  249.   GLfloat floor_col[] =
  250.   {0.7, 0.7, 0.7};
  251.   GLfloat floor_norm[] =
  252.   {0.0, 0.0, 1.0};
  253.   GLfloat floor_verts[4][3] =
  254.   {
  255.     {4.0, 4.0, 0.0},
  256.     {-4.0, 4.0, 0.0},
  257.     {-4.0, -4.0, 0.0},
  258.     {4.0, -4.0, 0.0}};
  259.   GLfloat sphere_col[] =
  260.   {0.7, 0.1, 0.2};
  261.   GLfloat box_col[] =
  262.   {0.1, 0.2, 0.7};
  263.   GLfloat box_verts[6][4][3] =
  264.   {
  265.     {
  266.       {1.0, -1.0, -1.0},
  267.       {-1.0, -1.0, -1.0},
  268.       {-1.0, 1.0, -1.0},
  269.       {1.0, 1.0, -1.0}},
  270.     {
  271.       {1.0, -1.0, 1.0},
  272.       {1.0, -1.0, -1.0},
  273.       {1.0, 1.0, -1.0},
  274.       {1.0, 1.0, 1.0}},
  275.     {
  276.       {-1.0, -1.0, 1.0},
  277.       {1.0, -1.0, 1.0},
  278.       {1.0, 1.0, 1.0},
  279.       {-1.0, 1.0, 1.0}},
  280.     {
  281.       {-1.0, -1.0, -1.0},
  282.       {-1.0, -1.0, 1.0},
  283.       {-1.0, 1.0, 1.0},
  284.       {-1.0, 1.0, -1.0}},
  285.     {
  286.       {1.0, 1.0, 1.0},
  287.       {1.0, 1.0, -1.0},
  288.       {-1.0, 1.0, -1.0},
  289.       {-1.0, 1.0, 1.0}},
  290.     {
  291.       {1.0, -1.0, -1.0},
  292.       {1.0, -1.0, 1.0},
  293.       {-1.0, -1.0, 1.0},
  294.       {-1.0, -1.0, -1.0}}};
  295.   GLfloat box_norm[6][3] =
  296.   {
  297.     {0, 0, -1},
  298.     {1, 0, 0},
  299.     {0, 0, 1},
  300.     {-1, 0, 0},
  301.     {0, 1, 0},
  302.     {0, -1, 0}};
  303.   GLUquadricObj *q;
  304.   int i;
  305.  
  306.   glNewList(SCENE, GL_COMPILE);
  307.  
  308.   glBegin(GL_QUADS);    /* draw the floor */
  309.   glNormal3fv(floor_norm);
  310.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, floor_col);
  311.   for (i = 0; i < 4; i++)
  312.     glVertex3fv(floor_verts[i]);
  313.   glEnd();
  314.  
  315.   q = gluNewQuadric();
  316.   XFORM(glPushMatrix();
  317.     glTranslatef(1.0, 1.0, 1.01));
  318.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_col);
  319.   gluSphere(q, 1.0, 40, 40);
  320.   XFORM(glPopMatrix());
  321.  
  322.   XFORM(glPushMatrix();
  323.     glTranslatef(-1.0, -1.0, 1.01));
  324.   for (i = 0; i < 6; i++) {
  325.     glBegin(GL_QUADS);
  326.     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, box_col);
  327.     glNormal3fv(box_norm[i]);
  328.     glVertex3fv(box_verts[i][0]);
  329.     glVertex3fv(box_verts[i][1]);
  330.     glVertex3fv(box_verts[i][2]);
  331.     glVertex3fv(box_verts[i][3]);
  332.     glEnd();
  333.   }
  334.   XFORM(glPopMatrix());
  335.   glEndList();
  336. }
  337.  
  338. static void 
  339. init(void)
  340. {
  341.   GLfloat ambient[] =
  342.   {0.1, 0.1, 0.1, 1.0};
  343.   GLfloat diffuse[] =
  344.   {0.8, 0.7, 0.8, 1.0};
  345.   GLfloat specular[] =
  346.   {0.5, 0.6, 0.8, 1.0};
  347.   GLfloat p[4];
  348.  
  349.   create_scene();
  350.   glClearColor(0.0, 0.0, 0.0, 1.0);
  351.   glClearDepth(1.0);
  352.   glEnable(GL_DEPTH_TEST);
  353.   glEnable(GL_POLYGON_SMOOTH);
  354.   glEnable(GL_LIGHTING);
  355.   glEnable(GL_LIGHT0);
  356.   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  357.   glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
  358.   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
  359.   glLightfv(GL_LIGHT0, GL_POSITION, lv);
  360.  
  361.   glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  362.   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  363.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  364.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  365.  
  366.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  367.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  368.  
  369.   if (shadows_supported) {
  370. #ifdef GL_SGIX_shadow_ambient
  371.     if (ambient_shadows)
  372.       glTexParameterf(GL_TEXTURE_2D, GL_SHADOW_AMBIENT_SGIX, 0.6);
  373. #endif
  374. #ifdef GL_SGIX_shadow
  375.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_TRUE);
  376.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_OPERATOR_SGIX,
  377.       GL_TEXTURE_LEQUAL_R_SGIX);
  378. #endif
  379.   }
  380.   /* Enable texgen to get texture-coods (x, y, z, w) at every point.These
  381.      texture co-ordinates are then transformed by the texture matrix.  */
  382.   glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  383.   glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  384.   glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  385.   glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  386.  
  387.   p[0] = 1.0;
  388.   p[1] = p[2] = p[3] = 0.0;
  389.   glTexGenfv(GL_S, GL_OBJECT_PLANE, p);
  390.  
  391.   p[0] = 0.0;
  392.   p[1] = 1.0;
  393.   p[2] = p[3] = 0.0;
  394.   glTexGenfv(GL_T, GL_OBJECT_PLANE, p);
  395.  
  396.   p[0] = p[1] = 0.0;
  397.   p[2] = 1.0, p[3] = 0.0;
  398.   glTexGenfv(GL_R, GL_OBJECT_PLANE, p);
  399.  
  400.   p[0] = p[1] = p[2] = 0.0;
  401.   p[3] = 1.0;
  402.   glTexGenfv(GL_Q, GL_OBJECT_PLANE, p);
  403.  
  404.   glEnable(GL_TEXTURE_GEN_S);
  405.   glEnable(GL_TEXTURE_GEN_T);
  406.   glEnable(GL_TEXTURE_GEN_R);
  407.   glEnable(GL_TEXTURE_GEN_Q);
  408. }
  409.  
  410. int
  411. main(int argc, char *argv[])
  412. {
  413.   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
  414.   glutInitWindowSize(width, height);
  415.   glutCreateWindow("Shadow Map");
  416.  
  417.   if (glutExtensionSupported("GL_SGIX_shadow") &&
  418.     glutExtensionSupported("GL_EXT_subtexture") &&
  419.     glutExtensionSupported("GL_EXT_copy_texture")) {
  420.     shadows_supported = GL_TRUE;
  421.     ambient_shadows = glutExtensionSupported("GL_SGIX_shadow_ambient");
  422.     depth_texture = glutExtensionSupported("GL_SGIX_depth_texture");
  423.   } else {
  424.     fprintf(stderr, "shadowmap: uses several OpenGL extensions to operate fully:\n");
  425.     fprintf(stderr, "  GL_SGIX_shadow\n");
  426.     fprintf(stderr, "  GL_SGIX_shadow_ambient\n");
  427.     fprintf(stderr, "  GL_SGIS_depth_texture\n");
  428.     fprintf(stderr, "  GL_EXT_subtexture\n");
  429.     fprintf(stderr, "  GL_EXT_copy_texture\n");
  430.   }
  431.  
  432.   init();
  433.   glutReshapeFunc(reshape);
  434.   glutDisplayFunc(display);
  435.   glutMotionFunc(motion);
  436.   glutMouseFunc(mouse);
  437.   glutKeyboardFunc(key);
  438.   glutCreateMenu(menu);
  439.   glutAddMenuEntry("Normal view", M_NORMAL);
  440.   glutAddMenuEntry("Light view", M_LIGHT);
  441.   glutAddMenuEntry("Projective textures", M_PROJTEX);
  442.   if (shadows_supported)
  443.     glutAddMenuEntry("Shadows", M_SHADOW);
  444.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  445.   glutMainLoop();
  446.   return 0;             /* ANSI C requires main to return int. */
  447. }
  448.